﻿/*
   Copyright 2012 University of Southampton

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using uk.ac.soton.ses.DAL;
using System.IO;

namespace uk.ac.soton.ses
{
    public class ExperimentBO
    {
        public ExperimentBO()
        {
        }

        public ExperimentBO(Experiment experimentDB)
        {
            this.ID = experimentDB.ID;
            this.Name = experimentDB.Name;
            //this.OwnerID = experimentDB.Owner;
            //this.UserName = experimentDB.User.Username;
            this.Date = experimentDB.Date;
            this.Description = experimentDB.Description;
            this.ExperimentTypeID = experimentDB.ExperimentType == null ? (int)HDCExperimentTypes.None:experimentDB.ExperimentType.ID;
            this.DefaultBasePath = experimentDB.DefaultBasePath;
            this.IsDeleted = experimentDB.IsDeleted;
            this.RowVersion = experimentDB.RowVersion;
            this.FileSystemUserID = experimentDB.FileSystemUserID;
            this.ReadUsers = experimentDB.UserAccesses.Where(ace => !ace.WriteAccessGranted).Select(ace => ace.User.UserID).ToArray();
            this.WriteUsers = experimentDB.UserAccesses.Where(ace => ace.WriteAccessGranted).Select(ace => ace.User.UserID).ToArray();
        }

        [XmlAttribute("ID")]
        public int ID { get; set; }

        [XmlAttribute("name")]
        public string Name { get; set; }

        //[XmlAttribute("ownerID")]
        //public int OwnerID { get; set; }

        [XmlAttribute("date")]
        public DateTime Date { get; set; }

        [XmlAttribute("description")]
        public string Description { get; set; }

        [XmlAttribute("experimentTypeID")]
        public int ExperimentTypeID { get; set; }

        [XmlAttribute("defaultBasePath")]
        public string DefaultBasePath { get; set; }

        [XmlAttribute("isDeleted")]
        public bool IsDeleted { get; set; }

        [XmlAttribute("rowVersion")]
        public byte[] RowVersion { get; set; }

        //[XmlIgnore()]
        //public string UserName { get; set; }

        [XmlAttribute("fileSystemUserID")]
        public string FileSystemUserID { get; set; }

        [XmlAttribute("readUsers")]
        public string[] ReadUsers { get; set; }

        [XmlAttribute("writeUsers")]
        public string[] WriteUsers { get; set; }
    }

    public class ExperimentDataFileBO
    {
        //Fields
        private string _basePath = "";
        private string _remainingPath = "";
        private string _fullPath = "";
        private string _objectName = "";
        private string _objectFolder = "";

        //Properties
        [XmlAttribute("ID")]
        public int ID { get; set; }

        [XmlAttribute("experimentID")]
        public int ExperimentID { get; set; }

        [XmlAttribute("experimentDatatypeID")]
        public int ExperimentDatatypeID { get; set; }

        [XmlAttribute("description")]
        public string Description { get; set; }

        [XmlAttribute("basePath")]
        public string BasePath
        {
            get { return this._basePath; }
            set
            {
                this._basePath = value;
                this.SetOtherPaths();
            }
        }

        [XmlAttribute("remainingPath")]
        public string RemainingPath
        {
            get { return this._remainingPath; }
            set
            {
                this._remainingPath = value;
                this.SetOtherPaths();
            }
        }

        [XmlAttribute("lastWriteTime")]
        public DateTime LastWriteTime { get; set; }

        [XmlAttribute("creationTime")]
        public DateTime CreationTime { get; set; }

        [XmlAttribute("lastAccessTime")]
        public DateTime LastAccessTime { get; set; }

        [XmlAttribute("fileSize")]
        public Int64 FileSize { get; set; }

        [XmlAttribute("sha1Hash")]
        public string SHA1Hash { get; set; }

        [XmlAttribute("sha1HashGeneratedTime")]
        public DateTime SHA1HashGeneratedTime { get; set; }

        [XmlAttribute("fileSystemUserID")]
        public string FileSystemUserID { get; set; }

        [XmlAttribute("isDeleted")]
        public bool IsDeleted { get; set; }

        [XmlAttribute("rowVersion")]
        public byte[] RowVersion { get; set; }

        [XmlIgnore()]
        public string FullPath { get { return this._fullPath; } }

        /// <summary>
        /// We need this because the data item's RemainingPath is sometimes subdir\file.txt whereas ObjectName should give us just file.txt
        /// </summary>
        [XmlIgnore()]
        public string ObjectName { get { return this._objectName; } }

        /// <summary>
        /// We need this because the data item's BasePath might not include the full path to the file (as it does not include sub directories)
        /// </summary>
        [XmlIgnore()]
        public string ObjectFolder { get { return this._objectFolder; } }
        
        public ExperimentDataFileBO()
        {
        }

        public ExperimentDataFileBO(ExperimentDataFile experimentDataFileDB)
        {
            //Note, ?? is the null coalescing operator which will use the value to the right if the value to the left of it is null
            this.ID = experimentDataFileDB.ID;
            this.RemainingPath = experimentDataFileDB.Filename;
            this.Description = experimentDataFileDB.Description;
            this.BasePath = experimentDataFileDB.BasePath;
            this.LastWriteTime = experimentDataFileDB.LastWriteTime;
            this.CreationTime = experimentDataFileDB.CreationTime ?? default(DateTime);
            this.LastAccessTime = experimentDataFileDB.LastAccessTime ?? default(DateTime);
            this.FileSize = experimentDataFileDB.FileSize ?? -1;
            this.SHA1Hash = experimentDataFileDB.SHA1Hash;
            this.SHA1HashGeneratedTime = experimentDataFileDB.SHA1HashGeneratedTime ?? default(DateTime);
            this.IsDeleted = experimentDataFileDB.IsDeleted;
            this.RowVersion = experimentDataFileDB.RowVersion;
            this.FileSystemUserID = experimentDataFileDB.FileSystemUserID;
            this.ExperimentID = experimentDataFileDB.Experiment.ID;
            this.ExperimentDatatypeID = experimentDataFileDB.ExperimentDataFileType == null ? -1 :experimentDataFileDB.ExperimentDataFileType.ID;
        }

        public bool Matches(ExperimentDataFileBO obj) //Not overriding Equals because we're not quite doing a complete match
        {
            if (obj == null)
            {
                return false;
            }

            bool objectsAreEqual =
                   (obj.RemainingPath.Equals(this.RemainingPath, StringComparison.OrdinalIgnoreCase))
                && (obj.BasePath.Equals(this.BasePath, StringComparison.OrdinalIgnoreCase))
                //&& (obj.Description == this.Description)
                && (obj.FileSize == this.FileSize)
                //&& (obj.LastAccessTime == this.LastAccessTime)
                && (obj.CreationTime == this.CreationTime)
                && (obj.LastWriteTime == this.LastWriteTime)
                && (obj.SHA1Hash == this.SHA1Hash);

            return objectsAreEqual;
        }

        private void SetOtherPaths()
        {
            this._fullPath = Path.Combine(this._basePath, this._remainingPath);
            FileInfo fi = new FileInfo(this.FullPath);

            this._objectName = fi.Name;
            this._objectFolder = fi.DirectoryName;
        }


    }
}